package com.eman.m.n.km_printer_plugin;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.util.Base64;
import android.util.Log;

import androidx.annotation.NonNull;

import com.alibaba.fastjson.JSONObject;
import com.android.print.sdk.PrinterConstants;
import android.src.main.km_printer_plugin.bean.BltDevice;
import android.src.main.km_printer_plugin.constant.EventChannelConstant;
import android.src.main.km_printer_plugin.manager.PrintfManager;
import android.src.main.km_printer_plugin.manager.ThreadPoolManager;
import android.src.main.km_printer_plugin.utils.PermissionUtil;
import android.src.main.km_printer_plugin.utils.Util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;

/** KmPrinterPlugin */
public class KmPrinterPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private MethodChannel methodChannel;
  private EventChannel eventChannel;

  private static final String METHOD_CHANNEL_PRINT = "android.bluetooth.print.km/method";
  private static final String EVENT_CHANNEL_PRINT = "android.bluetooth.print.km/event";
  private static final String TAG = "KmPrinterPlugin";

  private static Context applicationContext;
  private BroadcastReceiver kmPrinterReceiver;
  private Activity activity;

  private android.src.main.km_printer_plugin.manager.PrintfManager printfManager;
  private PrintfManager.BluetoothChangLister bluetoothChangLister;

  private BluetoothManager bluetoothManager;
  private BluetoothAdapter bluetoothAdapter;
//  private AbstractList<BluetoothDevice> bluetoothDeviceArrayList;
//  private List<BluetoothDevice> bondedDeviceArrayList;
  private List<android.src.main.km_printer_plugin.bean.BltDevice> bluetoothDevices;
  private List<BltDevice> bondedDevices;
  private static final int REQUEST_ENABLE_BT = 2;

  // flutter消息通知通道
  private EventChannel.EventSink ecEventSink = null;
  private final EventChannel.StreamHandler streamHandler = new EventChannel.StreamHandler() {

    @Override
    public void onListen(Object o, EventChannel.EventSink eventSink) {
      ecEventSink = eventSink;
//      PrintfManager.getInstance(applicationContext).addBluetoothChangLister(bluetoothChangLister);
    }

    @Override
    public void onCancel(Object o) {
      try {
        applicationContext.unregisterReceiver(kmPrinterReceiver);
      } catch (Exception e) {
        Log.e(TAG, e.getLocalizedMessage() == null ? "" : e.getLocalizedMessage());
      }
//      printfManager.removeBluetoothChangLister(bluetoothChangLister);
      ecEventSink = null;
    }
  };

  private String sendString(BltDevice bltDevice) {
    StringBuilder builder = new StringBuilder();
    if (bltDevice.getName() == null) {
      builder.append("{\"address\":\"").append(bltDevice.getAddress()).append("\"}");
    } else {
      builder.append("{\"name\":\"").append(bltDevice.getName())
              .append("\",\"address\":\"").append(bltDevice.getAddress()).append("\"}");
    }
    return builder.toString();
  }

  private String sendString(List<BltDevice> bltDeviceList) {
    StringBuilder builder = new StringBuilder("[");
    for (BltDevice bltDevice : bltDeviceList) {
      if (bltDevice.getName() == null) {
        builder.append("{\"address\":\"").append(bltDevice.getAddress()).append("\"},");
      } else {
        builder.append("{\"name\":\"").append(bltDevice.getName())
                .append("\",\"address\":\"").append(bltDevice.getAddress()).append("\"},");
      }
    }
    builder.append("]");
    if (builder.lastIndexOf(",") != -1) {
      builder.deleteCharAt(builder.lastIndexOf(","));
    }
    return builder.toString();
  }

  // 发送给flutter
  private Map<String, Object> sendEvent(int code, Object obj) {
    Map<String, Object> map = new HashMap<>();
    map.put("code", code);
    if (obj != null) {
//      map.put("data", JSONObject.toJSON(obj));
      map.put("data", obj);
    }
    return map;
  }

  // 发送给flutter
  private Map<String, Object> sendEvent(int code) {
    Map<String, Object> map = new HashMap<>();
    map.put("code", code);
    return map;
  }

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    mOnAttachedToEngine(flutterPluginBinding.getApplicationContext(), flutterPluginBinding.getBinaryMessenger());
  }

  // 初始准备
  private void mOnAttachedToEngine(@NonNull Context applicationContext, @NonNull BinaryMessenger messenger) {
    initBroadcastReceiver();
    printfManager = PrintfManager.getInstance(applicationContext);
//    printfManager.defaultConnection();
//    printfManager.setConnectSuccess(new PrintfManager.ConnectSuccess() {
//      @Override
//      public void success() {
//        Log.d(TAG, "ConnectSuccess Close Current UI");
//      }
//    });
    bluetoothChangLister = new PrintfManager.BluetoothChangLister() {
      @Override
      public void chang(String name, String address) {
        if (ecEventSink != null) {
          ecEventSink.success(sendEvent(EventChannelConstant.BLUE_INFO,
                  sendString(new BltDevice(name, address))));
        }
      }
    };
    PrintfManager.getInstance(applicationContext).addBluetoothChangLister(bluetoothChangLister);

    // 创建通道
    KmPrinterPlugin.applicationContext = applicationContext;
    methodChannel = new MethodChannel(messenger, METHOD_CHANNEL_PRINT);
    methodChannel.setMethodCallHandler(this);
    eventChannel = new EventChannel(messenger, EVENT_CHANNEL_PRINT);
    eventChannel.setStreamHandler(streamHandler);

    // 蓝牙信息初始化
    bluetoothDevices = new ArrayList<>();
    bondedDevices = new ArrayList<>();
    bluetoothManager = (BluetoothManager) applicationContext.getSystemService(Context.BLUETOOTH_SERVICE);
    bluetoothAdapter = bluetoothManager.getAdapter();
//    getMBondedDevices();
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    switch (call.method) {
      case "getPlatformVersion":
        result.success("Android " + android.os.Build.VERSION.RELEASE);
        break;
      case "kmSharedStorePrinter":
        printfManager.defaultConnection();
        result.success(null);
        break;
      case "kmStartPrint":
        Double width = call.argument("width");
        Double height = call.argument("height");
        List<String> pics = call.argument("fileStrList");
        startPrint(width, height, pics);
        result.success(null);
        break;
      case "kmStartScan":
        if(PermissionUtil.checkLocationPermission(activity)){
          starSearchBlue();
        }
        result.success(null);
        break;
      case "kmStopScan":
        stopSearchBlue(false);
        result.success(null);
        break;
      case "kmOpenPrinter":
        String address1 = call.argument("address");
        BluetoothDevice device1 = bluetoothAdapter.getRemoteDevice(address1);
        openPrinter(device1);
        result.success(null);
        break;
      case "kmConnAndOpen":
        String address2 = call.argument("address");
        BluetoothDevice device2 = bluetoothAdapter.getRemoteDevice(address2);
        connAndOpen(device2);
        result.success(null);
        break;
      case "kmChangeBlueName":
        String name = call.argument("newName");
        changBlueName(name);
        result.success(null);
        break;
      default:
        result.notImplemented();
        break;
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    applicationContext = null;
    methodChannel.setMethodCallHandler(null);
    methodChannel = null;
    eventChannel.setStreamHandler(null);
    eventChannel = null;
    bluetoothAdapter = null;
    bluetoothManager = null;
    printfManager.removeBluetoothChangLister(bluetoothChangLister);
  }

  /**ActivityAware*/
  @Override
  public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) {
    activity = activityPluginBinding.getActivity();
//    PermissionUtil.checkLocationPermission(activity);
  }

  @Override
  public void onDetachedFromActivityForConfigChanges() {

  }

  @Override
  public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding activityPluginBinding) {

  }

  @Override
  public void onDetachedFromActivity() {
//    applicationContext = null;
//    methodChannel.setMethodCallHandler(null);
//    methodChannel = null;
//    eventChannel.setStreamHandler(null);
//    eventChannel = null;
//    bluetoothAdapter = null;
//    bluetoothManager = null;
  }

  private boolean judge(BluetoothDevice device, List<BluetoothDevice> devices) {
    if (device == null || devices.contains(device)) {
      return true;
    }
//    //Filter 1536 stands for printer
//    int majorDeviceClass = device.getBluetoothClass().getMajorDeviceClass();
//    if(majorDeviceClass != 1536){
//      return true;
//    }
    return false;
  }

  private Bitmap resizedBitmap1(byte[] bytes, int width, int height) {
    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
//    int bWidth = bitmap.getWidth();
//    int bHeight = bitmap.getHeight();
//    float scaleWidth = ((float) (width * 10) / bWidth);
//    float scaleHeight = ((float) (height * 10) / bHeight);
//    Matrix matrix = new Matrix();
//    matrix.postScale(scaleWidth, scaleHeight);
//    return Bitmap.createBitmap(bitmap, 0, 0,
//            bWidth, bHeight, matrix, true);
    Matrix matrix = new Matrix();
    matrix.postScale(0.5f, 0.5f); // 长和宽放大缩小的比例
//    matrix.setTranslate(300f, 50f); // 左->右 下->上平移
    return Bitmap.createBitmap(bitmap, 0, 0,
                bitmap.getWidth(), bitmap.getHeight(), matrix, true);
  }

  private Bitmap resizedBitmap2(byte[] bytes, int width, int height) {
    BitmapFactory.Options options = new BitmapFactory.Options();
//    options.outWidth = width;
//    options.outHeight = height;
    options.inSampleSize = 2;
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
  }

  private void startPrint(Double width, Double height, List<String> pics) {
    // 图片Base64处理
    if (width != null && height != null) {
//      String[] pics = picString.split(",");
      List<Bitmap> bitmaps = new ArrayList<>();
      for (String pic : pics) {
        byte[] bytes = Base64.decode(pic, Base64.DEFAULT);
        Bitmap bitmap = resizedBitmap1(bytes, width.intValue(), height.intValue());
        bitmaps.add(bitmap);
      }
      printfManager.printf(width.intValue(),height.intValue(), bitmaps, activity);
    }
  }

  private void starSearchBlue() {
    ecEventSink.success(sendEvent(EventChannelConstant.START_SCAN));
    Util.ToastText(applicationContext, "正在搜索...");
    bluetoothDevices.clear();
    IntentFilter filter = new IntentFilter();
    filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
    filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    filter.addAction(BluetoothDevice.ACTION_FOUND);
    filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
    applicationContext.registerReceiver(kmPrinterReceiver, filter);
    if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
      Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
      activity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    } else {
      bluetoothAdapter.startDiscovery();
    }
  }

  private void stopSearchBlue(boolean showText) {
    if (kmPrinterReceiver != null) {
      try {
        applicationContext.unregisterReceiver(kmPrinterReceiver);
      } catch (Exception e) {
        Log.e(TAG, e.getLocalizedMessage() == null ? "" : e.getLocalizedMessage());
      }
      if (showText) {
        Util.ToastText(applicationContext, "结束搜索");
      }
    }
    if (bluetoothAdapter != null) {
      bluetoothAdapter.cancelDiscovery();
    }
    ecEventSink.success(sendEvent(EventChannelConstant.STOP_SCAN));
  }

  private void openPrinter(final BluetoothDevice device) {
    ThreadPoolManager.getInstance().getCachedThreadPool().execute(new Runnable() {
      @Override
      public void run() {
        printfManager.openPrinter(device);
      }
    });
  }

  private void connAndOpen(final BluetoothDevice device) {
    Util.ToastText(applicationContext, "正在连接...");
    //先停止搜索
    stopSearchBlue(false);
    //进行配对
    ThreadPoolManager.getInstance().getCachedThreadPool().execute(new Runnable() {
      @Override
      public void run() {
        try {
          BluetoothDevice mDevice = bluetoothAdapter.getRemoteDevice(device.getAddress());
          printfManager.openPrinter(mDevice);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    });
  }

  private void changBlueName(String name) {
    if(!printfManager.isConnect()){
      Util.ToastText(applicationContext, "请先连接蓝牙");
    } else {
      printfManager.changBlueName(name);
    }
  }

  private void initBroadcastReceiver() {
    kmPrinterReceiver = new BroadcastReceiver() {
      @Override
      public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
          // 状态改变
          final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                  BluetoothAdapter.ERROR);
          switch (state) {
            case BluetoothAdapter.STATE_OFF:
              PrintfManager.getInstance(context).mHandler.sendEmptyMessage(PrinterConstants.Connect.CLOSED);
              ecEventSink.success(sendEvent(EventChannelConstant.BLUETOOTH_OFF));
              break;
            case BluetoothAdapter.STATE_TURNING_OFF:
              Log.d(TAG, "BLUETOOTH_TURNING_OFF");
              ecEventSink.success(sendEvent(EventChannelConstant.STATE_DISCONNECTED));
              break;
            case BluetoothAdapter.STATE_ON:
              ecEventSink.success(sendEvent(EventChannelConstant.BLUETOOTH_ON));
              break;
            case BluetoothAdapter.STATE_TURNING_ON:
              Log.d(TAG, "BLUETOOTH_TURNING_ON");
              ecEventSink.success(sendEvent(EventChannelConstant.STATE_CONNECTED));
              break;
          }
        }
        if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) { //蓝牙连接已经断开
          PrintfManager.getInstance(context).mHandler.sendEmptyMessage(PrinterConstants.Connect.CLOSED);
        }
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
          getMBondedDevices();
          BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
          if (device != null) {
            BltDevice bltDevice = new BltDevice(device.getName(), device.getAddress());
            // 未绑定的设备添加到新设备
            if (!bondedDevices.contains(bltDevice)) {
              // 新设备去重
              if (!bluetoothDevices.contains(bltDevice)) {
                bluetoothDevices.add(bltDevice);
              }
            }
          }
          Log.d(TAG, JSONObject.toJSONString(bluetoothDevices));
//          Util.ToastText(applicationContext, JSONObject.toJSONString(bluetoothDevices));
          ecEventSink.success(sendEvent(EventChannelConstant.BONDED_DEVICES, sendString(bondedDevices)));
          ecEventSink.success(sendEvent(EventChannelConstant.FOUND_DEVICES, sendString(bluetoothDevices)));
        }
        if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
          stopSearchBlue(true);
        }
      }
    };
  }

  /**
   * 获取绑定设备
   */
  private void getMBondedDevices() {
    Set<BluetoothDevice> bondedDevicesSet  = bluetoothAdapter.getBondedDevices();
    for (BluetoothDevice device : bondedDevicesSet) {
      BltDevice bltDevice = new BltDevice(device.getName(), device.getAddress());
      if (!bondedDevices.contains(bltDevice)) {
        bondedDevices.add(bltDevice);
      }
    }
  }
}
